home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / grafik / raytracing / rayshade-4.0.6.3 / inetray / irtrace.c < prev    next >
C/C++ Source or Header  |  1993-08-15  |  12KB  |  477 lines

  1. /*======================================================================
  2.                     I R T R A C E . C 
  3.                     doc: Tue Mar  3 10:50:23 1992
  4.                     dlm: Sun Jul  5 15:41:44 1992
  5.                     (c) 1992 ant@julia
  6.                     uE-Info: 154 74 T 0 0 72 2 2 8 ofnI
  7. ======================================================================*/
  8.  
  9. /*#define        FULL_SAMPLING*/
  10.  
  11. #include "rayshade.h"
  12. #include "libsurf/atmosphere.h"
  13. #include "libsurf/surface.h"
  14. #include "libcommon/sampling.h"
  15. #include "options.h"
  16. #include "stats.h"
  17. #include "viewing.h"
  18. #include "picture.h"
  19. #include "irtrace.h"
  20.  
  21. #define UNSAMPLED    -1
  22. #define SUPERSAMPLED    -2
  23.  
  24. static void    FullySamplePixel();        /* private routines */
  25. static void    AdaptiveRefineScanline();
  26. static void     FullySampleScanline();
  27. static void    SingleSampleScanline();
  28. static int    ExcessiveContrast();
  29. static Float    SampleTime();
  30.  
  31. static Ray    TopRay;                /* Top-level ray. */
  32. static int    *SampleNumbers;
  33. static Scanline *scan;
  34.  
  35. /*
  36.  * "Dither matrices" used to encode the 'number' of a ray that samples a
  37.  * particular portion of a pixel.  Hand-coding is ugly, but...
  38.  */
  39. static int OneSample[1] =     {0};
  40. static int TwoSamples[4] =    {0, 2,
  41.                  3, 1};
  42. static int ThreeSamples[9] =    {0, 2, 7,
  43.                  6, 5, 1,
  44.                  3, 8, 4};
  45. static int FourSamples[16] =    { 0,  8,  2, 10,
  46.                  12,  4, 14,  6,
  47.                   3, 11,  1,  9,
  48.                  15,  7, 13,  5};
  49. static int FiveSamples[25] =    { 0,  8, 23, 17,  2,
  50.                  19, 12,  4, 20, 15,
  51.                   3, 21, 16,  9,  6,
  52.                  14, 10, 24,  1, 13,
  53.                  22,  7, 18, 11,  5};
  54. static int SixSamples[36] =    { 6, 32,  3, 34, 35,  1,
  55.                   7, 11, 27, 28,  8, 30,
  56.                  24, 14, 16, 15, 23, 19,
  57.                  13, 20, 22, 21, 17, 18,
  58.                  25, 29, 10,  9, 26, 12,
  59.                  36,  5, 33,  4,  2, 31};
  60. static int SevenSamples[49] =    {22, 47, 16, 41, 10, 35,  4,
  61.                   5, 23, 48, 17, 42, 11, 29,
  62.                  30,  6, 24, 49, 18, 36, 12,
  63.                  13, 31,  7, 25, 43, 19, 37,
  64.                  38, 14, 32,  1, 26, 44, 20,
  65.                  21, 39,  8, 33,  2, 27, 45,
  66.                  46, 15, 40,  9, 34,  3, 28};
  67. static int EightSamples[64] =    { 8, 58, 59,  5,  4, 62, 63,  1,
  68.                  49, 15, 14, 52, 53, 11, 10, 56,
  69.                  41, 23, 22, 44, 45, 19, 18, 48,
  70.                  32, 34, 35, 29, 28, 38, 39, 25,
  71.                  40, 26, 27, 37, 36, 30, 31, 33,
  72.                  17, 47, 46, 20, 21, 43, 42, 24,
  73.                   9, 55, 54, 12, 13, 51, 50, 16,
  74.                  64,  2,  3, 61, 60,  6,  7, 57};
  75.  
  76. RaytraceInit(argc, argv)
  77. int argc;
  78. char **argv;
  79. {
  80.     RSInitialize(argc,argv);
  81.     switch (Sampling.sidesamples) {
  82.         case 1:
  83.             SampleNumbers = OneSample;
  84.             break;
  85.         case 2:
  86.             SampleNumbers = TwoSamples;
  87.             break;
  88.         case 3:
  89.             SampleNumbers = ThreeSamples;
  90.             break;
  91.         case 4:
  92.             SampleNumbers = FourSamples;
  93.             break;
  94.         case 5:
  95.             SampleNumbers = FiveSamples;
  96.             break;
  97.         case 6:
  98.             SampleNumbers = SixSamples;
  99.             break;
  100.         case 7:
  101.             SampleNumbers = SevenSamples;
  102.             break;
  103.         case 8:
  104.             SampleNumbers = EightSamples;
  105.             break;
  106.         default:
  107.             RLerror(RL_PANIC,
  108.                 "Sorry, %d rays/pixel not supported.\n",
  109.                     Sampling.totsamples);
  110.     }
  111.     return Screen.xsize;
  112. }
  113.  
  114. Scanline *Raytrace(bSz,lNr)
  115. int bSz,lNr;
  116. {
  117.     int x,y,i;
  118.  
  119.     /* ----------- */
  120.     /* alloc stuff */
  121.     /* ----------- */
  122.     scan = (Scanline *)Malloc((bSz+2)*sizeof(Scanline));
  123.     if (scan == NULL) {
  124.         fprintf(stderr,"Malloc() failed\n");
  125.         exit(1);
  126.     }
  127.     for (y=0; y<bSz+2; y++) {
  128.         scan[y].pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
  129.             if (scan[y].pix == NULL) {
  130.                     fprintf(stderr,"Malloc() failed\n");
  131.                     exit(1);
  132.         }
  133.             scan[y].samp = (int *)Malloc(Screen.xsize * sizeof(int));
  134.             if (scan[y].samp == NULL) {
  135.                     fprintf(stderr,"Malloc() failed\n");
  136.                     exit(1);
  137.         }
  138.     }
  139.  
  140.     /* ------- */
  141.     /* Top Ray */
  142.     /* ------- */
  143.     TopRay.pos = Camera.pos;
  144.     TopRay.media = (Medium *)0;
  145.     TopRay.depth = 0;
  146.  
  147.     /* ----------- */
  148.     /* Trace Block */
  149.     /* ----------- */
  150. #ifdef FULL_SAMPLING
  151.     for (y=0; y<bSz; y++)
  152.         FullySampleScanline(y+lNr,&scan[y+1]);
  153. #else
  154.     if (bSz == 1) {                    /* special case */
  155.         FullySampleScanline(lNr,&scan[1]);
  156.         return scan;
  157.     }
  158.     x = Screen.xsize-1;
  159.     SingleSampleScanline(lNr+1,&scan[2]);
  160.     FullySamplePixel(0, lNr+1, &scan[2].pix[0],
  161.                    &scan[2].samp[0]);
  162.     FullySamplePixel(x, lNr+1, &scan[2].pix[x],
  163.                    &scan[2].samp[x]); 
  164.     if (lNr == 0) {                    /* first block */
  165.         FullySampleScanline(0,&scan[1]);
  166.     } else {                    /* 2nd to last */
  167.         SingleSampleScanline(lNr-1,&scan[0]);
  168.         FullySamplePixel(0, lNr-1, &scan[0].pix[0],
  169.                        &scan[0].samp[0]);
  170.         FullySamplePixel(x, lNr-1, &scan[0].pix[x],
  171.                        &scan[0].samp[x]); 
  172.         SingleSampleScanline(lNr,&scan[1]);
  173.         FullySamplePixel(0, lNr, &scan[1].pix[0],
  174.                      &scan[1].samp[0]);
  175.         FullySamplePixel(x, lNr, &scan[1].pix[x],
  176.                      &scan[1].samp[x]);
  177.         if (Sampling.sidesamples > 1)
  178.             AdaptiveRefineScanline(lNr,
  179.                 &scan[0],
  180.                 &scan[1],
  181.                 &scan[2]); 
  182.     }
  183.     
  184.     for (y=lNr+1,i=3; i<bSz; y++,i++) {        /* main part */
  185.         SingleSampleScanline(y+1,&scan[i]);
  186.         FullySamplePixel(0, y+1, &scan[i].pix[0],
  187.                      &scan[i].samp[0]);
  188.         FullySamplePixel(x, y+1, &scan[i].pix[x],
  189.                      &scan[i].samp[x]);
  190.         if (Sampling.sidesamples > 1)
  191.             AdaptiveRefineScanline(y,
  192.                 &scan[i-2],
  193.                 &scan[i-1],
  194.                 &scan[i]); 
  195.     }
  196.  
  197.     if (lNr+bSz == Screen.ysize) {            /* last block */
  198.         FullySampleScanline(lNr+bSz-1,&scan[bSz]);
  199.         if (Sampling.sidesamples > 1)
  200.             AdaptiveRefineScanline(lNr+bSz-1,
  201.                 &scan[bSz-2],
  202.                 &scan[bSz-1],
  203.                 &scan[bSz]); 
  204.     } else {                    /* 1st - 2nd to last */
  205.          y = lNr+bSz-1;
  206.         SingleSampleScanline(y,&scan[bSz]);
  207.         FullySamplePixel(0, y, &scan[bSz].pix[0],
  208.                        &scan[bSz].samp[0]);
  209.         FullySamplePixel(x, y, &scan[bSz].pix[x],
  210.                        &scan[bSz].samp[x]);
  211.         if (Sampling.sidesamples > 1)
  212.             AdaptiveRefineScanline(y-1,
  213.                 &scan[bSz-2],
  214.                 &scan[bSz-1],
  215.                 &scan[bSz]); 
  216.         y = lNr+bSz;
  217.         SingleSampleScanline(y,&scan[bSz+1]);
  218.         FullySamplePixel(0, y, &scan[bSz+1].pix[0],
  219.                        &scan[bSz+1].samp[0]);
  220.         FullySamplePixel(x, y, &scan[bSz+1].pix[x],
  221.                        &scan[bSz+1].samp[x]);
  222.         if (Sampling.sidesamples > 1)
  223.             AdaptiveRefineScanline(y-1,
  224.                 &scan[bSz-1],
  225.                 &scan[bSz],
  226.                 &scan[bSz+1]);
  227.     }
  228. #endif
  229.     return scan;
  230. }
  231.  
  232. static void
  233. SingleSampleScanline(line, data)
  234. int line;
  235. Scanline *data;
  236. {
  237.     Float upos, vpos, yp;
  238.     int x, usamp, vsamp;
  239.     Pixel tmp;
  240.  
  241.     yp = line + Screen.miny - 0.5*Sampling.filterwidth;
  242.     for (x = 0; x < Screen.xsize; x++) {
  243.         /*
  244.          * Pick a sample number...
  245.          */
  246.         data->samp[x] = nrand() * Sampling.totsamples;
  247.         /*
  248.          * Take sample corresponding to sample #.
  249.          */
  250.         usamp = data->samp[x] % Sampling.sidesamples;
  251.         vsamp = data->samp[x] / Sampling.sidesamples;
  252.  
  253.         vpos = yp + vsamp * Sampling.filterdelta;
  254.         upos = x + Screen.minx - 0.5*Sampling.filterwidth +
  255.                 usamp*Sampling.filterdelta;
  256.         if (Options.jitter) {
  257.             vpos += nrand()*Sampling.filterdelta;
  258.             upos += nrand()*Sampling.filterdelta;
  259.         }
  260.         TopRay.time = SampleTime(SampleNumbers[data->samp[x]]);
  261.         SampleScreen(upos, vpos, &TopRay,
  262.             &data->pix[x], SampleNumbers[data->samp[x]]);
  263.         if (Options.samplemap)
  264.             data->pix[x].alpha = 0;
  265.     }
  266. }
  267.  
  268. static void
  269. FullySampleScanline(line, data)
  270. int line;
  271. Scanline *data;
  272. {
  273.     int x;
  274.  
  275.     for (x = 0; x < Screen.xsize; x++) {
  276.         data->samp[x] = UNSAMPLED;
  277.         FullySamplePixel(x, line, &data->pix[x], &data->samp[x]);
  278.     }
  279. }
  280.  
  281. static void
  282. FullySamplePixel(xp, yp, pix, prevsamp)
  283. int xp, yp;
  284. Pixel *pix;
  285. int *prevsamp;
  286. {
  287.     Float upos, vpos, u, v;
  288.     int x, y, sampnum;
  289.     Pixel ctmp;
  290.  
  291.     if (*prevsamp == SUPERSAMPLED)
  292.         return;    /* already done */
  293.  
  294.     Stats.SuperSampled++;
  295.     if (*prevsamp == UNSAMPLED) {
  296.         /*
  297.          * No previous sample; initialize to black.
  298.          */
  299.         pix->r = pix->g = pix->b = pix->alpha = 0.;
  300.     } else {
  301.         if (Sampling.sidesamples == 1) {
  302.             *prevsamp = SUPERSAMPLED;
  303.             return;
  304.         }
  305.         x = *prevsamp % Sampling.sidesamples;
  306.         y = *prevsamp / Sampling.sidesamples;
  307.         pix->r *= Sampling.filter[x][y];
  308.         pix->g *= Sampling.filter[x][y];
  309.         pix->b *= Sampling.filter[x][y];
  310.         pix->alpha *= Sampling.filter[x][y];
  311.     }
  312.  
  313.     sampnum = 0;
  314.     xp += Screen.minx;
  315.     vpos = Screen.miny + yp - 0.5*Sampling.filterwidth;
  316.     for (y = 0; y < Sampling.sidesamples; y++,
  317.          vpos += Sampling.filterdelta) {
  318.         upos = xp - 0.5*Sampling.filterwidth;
  319.         for (x = 0; x < Sampling.sidesamples; x++,
  320.              upos += Sampling.filterdelta) {
  321.             if (sampnum != *prevsamp) {
  322.                 if (Options.jitter) {
  323.                     u = upos + nrand()*Sampling.filterdelta;
  324.                     v = vpos + nrand()*Sampling.filterdelta;
  325.                 } else {
  326.                     u = upos;
  327.                     v = vpos;
  328.                 }
  329.                 TopRay.time = SampleTime(SampleNumbers[sampnum]);
  330.                 SampleScreen(u, v, &TopRay, &ctmp,
  331.                     SampleNumbers[sampnum]);
  332.                 pix->r += ctmp.r*Sampling.filter[x][y];
  333.                 pix->g += ctmp.g*Sampling.filter[x][y];
  334.                 pix->b += ctmp.b*Sampling.filter[x][y];
  335.                 pix->alpha += ctmp.alpha*Sampling.filter[x][y];
  336.             }
  337.             if (++sampnum == Sampling.totsamples)
  338.                 sampnum = 0;
  339.         }
  340.     }
  341.  
  342.     if (Options.samplemap)
  343.         pix->alpha = 255;
  344.  
  345.     *prevsamp = SUPERSAMPLED;
  346. }
  347.  
  348. static void
  349. AdaptiveRefineScanline(y, scan0, scan1, scan2)
  350. int y;
  351. Scanline *scan0, *scan1, *scan2;
  352. {
  353.     int x, done;
  354.  
  355.     /*
  356.      * Walk down scan1, looking at 4-neighbors for excessive contrast.
  357.      * If found, supersample *all* neighbors not already supersampled.
  358.      * The process is repeated until either there are no
  359.      * high-contrast regions or all such regions are already supersampled.
  360.      */
  361.  
  362.     do {
  363.         done = TRUE;
  364.         for (x = 1; x < Screen.xsize -1; x++) {
  365.             /*
  366.               * Find min and max RGB for area we care about
  367.              */
  368.             if (ExcessiveContrast(x, scan0->pix, scan1->pix,
  369.                 scan2->pix)) {
  370.                 if (scan1->samp[x-1] != SUPERSAMPLED) {
  371.                     done = FALSE;
  372.                     FullySamplePixel(x-1, y,
  373.                         &scan1->pix[x-1],
  374.                         &scan1->samp[x-1]);
  375.                 }
  376.                 if (scan0->samp[x] != SUPERSAMPLED) {
  377.                     done = FALSE;
  378.                     FullySamplePixel(x, y-1,
  379.                         &scan0->pix[x],
  380.                         &scan0->samp[x]);
  381.                 }
  382.                 if (scan1->samp[x+1] != SUPERSAMPLED) {
  383.                     done = FALSE;
  384.                     FullySamplePixel(x+1, y,
  385.                         &scan1->pix[x+1],
  386.                         &scan1->samp[x+1]);
  387.                 }
  388.                 if (scan2->samp[x] != SUPERSAMPLED) {
  389.                     done = FALSE;
  390.                     FullySamplePixel(x, y+1,
  391.                         &scan2->pix[x],
  392.                         &scan2->samp[x]);
  393.                 }
  394.                 if (scan1->samp[x] != SUPERSAMPLED) {
  395.                     done = FALSE;
  396.                     FullySamplePixel(x, y,
  397.                         &scan1->pix[x],
  398.                         &scan1->samp[x]);
  399.                 }
  400.             }
  401.         }
  402.     } while (!done);
  403. }
  404.  
  405. static int
  406. ExcessiveContrast(x, pix0, pix1, pix2)
  407. int x;
  408. Pixel *pix0, *pix1, *pix2;
  409. {
  410.     Float mini, maxi, sum, diff;
  411.  
  412.     maxi = max(pix0[x].r, pix1[x-1].r);
  413.     if (pix1[x].r > maxi) maxi = pix1[x].r;
  414.     if (pix1[x+1].r > maxi) maxi = pix1[x+1].r;
  415.     if (pix2[x].r > maxi) maxi = pix2[x].r;
  416.  
  417.     mini = min(pix0[x].r, pix1[x-1].r);
  418.     if (pix1[x].r < mini) mini = pix1[x].r;
  419.     if (pix1[x+1].r < mini) mini = pix1[x+1].r;
  420.     if (pix2[x].r < mini) mini = pix2[x].r;
  421.  
  422.     diff = maxi - mini;
  423.     sum = maxi + mini;
  424.     if (sum > EPSILON && diff/sum > Options.contrast.r)
  425.         return TRUE;
  426.  
  427.     maxi = max(pix0[x].g, pix1[x-1].g);
  428.     if (pix1[x].g > maxi) maxi = pix1[x].g;
  429.     if (pix1[x+1].g > maxi) maxi = pix1[x+1].g;
  430.     if (pix2[x].g > maxi) maxi = pix2[x].g;
  431.  
  432.     mini = min(pix0[x].g, pix1[x-1].g);
  433.     if (pix1[x].g < mini) mini = pix1[x].g;
  434.     if (pix1[x+1].g < mini) mini = pix1[x+1].g;
  435.     if (pix2[x].g < mini) mini = pix2[x].g;
  436.  
  437.     diff = maxi - mini;
  438.     sum = maxi + mini;
  439.  
  440.     if (sum > EPSILON && diff/sum > Options.contrast.g)
  441.         return TRUE;
  442.  
  443.     maxi = max(pix0[x].b, pix1[x-1].b);
  444.     if (pix1[x].b > maxi) maxi = pix1[x].b;
  445.     if (pix1[x+1].b > maxi) maxi = pix1[x+1].b;
  446.     if (pix2[x].b > maxi) maxi = pix2[x].b;
  447.  
  448.     mini = min(pix0[x].b, pix1[x-1].b);
  449.     if (pix1[x].b < mini) mini = pix1[x].b;
  450.     if (pix1[x+1].b < mini) mini = pix1[x+1].b;
  451.     if (pix2[x].b < mini) mini = pix2[x].b;
  452.  
  453.     diff = maxi - mini;
  454.     sum = maxi + mini;
  455.     if (sum > EPSILON && diff/sum > Options.contrast.b)
  456.         return TRUE;
  457.  
  458.     return FALSE;
  459. }
  460.  
  461. static Float
  462. SampleTime(sampnum)
  463. int sampnum;
  464. {
  465.     Float window, jitter = 0.0, res;
  466.  
  467.     if (Options.shutterspeed <= 0.)
  468.         return Options.framestart;
  469.     if (Options.jitter)
  470.         jitter = nrand();
  471.     window = Options.shutterspeed / Sampling.totsamples;
  472.     res = Options.framestart + window * (sampnum + jitter);
  473.     TimeSet(res);
  474.     return res;
  475. }
  476.  
  477.